﻿// Gateway.Api 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
// 
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
// 
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using System.Text;
using Aurora.AI.Abstractions.Chats.Dtos;
using Aurora.AI.Common.Constants;
using Aurora.AI.Common.Extensions;
using Aurora.AI.Common.Helper;
using Aurora.AI.Common.Models;
using Aurora.AI.Common.Options;
using Aurora.AI.Wiki;
using Aurora.AI.Wiki.Domain.Domain.ChatApplications.Aggregates;
using Aurora.AI.Wiki.Models.Images;
using Aurora.AI.Wiki.Models.Videos;
using Aurora.AI.Wiki.Services;
using Aurora.AI.Wiki.Services.ChatApplication;
using Aurora.AI.Wiki.Services.Wiki;
using FileServer.Abstractions;
using FileServer.Abstractions.Models.Entities;
using Gateway.Domain.Entities;
using Microsoft.KernelMemory;
using Microsoft.KernelMemory.DataFormats.Text;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Plugins.Core;
using MemoryService = mem0.NET.Services.MemoryService;

namespace Gateway.UI.Api.AiServices;

/// <summary>
/// open ai service
/// </summary>
public class OpenAiService(
    ChatApplicationService chatApplicationService,
    WikiMemoryService wikiMemoryService,
    ILogger<OpenAiService> logger,
    WikiService wikiService,
    WikiSettingService wikiSettingService,
    IFileStorage fileStorage,
    IServiceProvider serviceProvider)
{
    /// <summary>
    /// 生成对话的主题
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public async Task GenerateTopicAsync(HttpContext context)
    {
        // 获取请求参数
        using var stream = new StreamReader(context.Request.Body);
        var message =
            JsonConvert.DeserializeObject<ChatCompletionRequest<ChatCompletionRequestMessage>>(
                await stream.ReadToEndAsync());
        var application = await chatApplicationService.Detail(message.ApplicationId);
        var commonSetting = await wikiSettingService.GetCommonSetting();
        var kernel = wikiMemoryService.CreateFunctionKernel(application.ChatModel, commonSetting);

        KernelFunction sunFun = kernel.Plugins.GetFunction("ConversationSummaryPlugin", "GetConversationTopics");
        context.Response.ContentType = "text/event-stream";
        Microsoft.SemanticKernel.ChatCompletion.ChatHistory chatMessageContents = new Microsoft.SemanticKernel.ChatCompletion.ChatHistory();
        chatMessageContents.AddSystemMessage("生成摘要,要求：精练、简洁，不超过20个字");
        var m= message.Messages.FirstOrDefault();
        chatMessageContents.Add(new ChatMessageContent(AuthorRole.User,"请问内容生成摘要，内容:"+ m.Content+ ",要求：精练、简洁，不超过20个字"));
       
        if (string.IsNullOrEmpty(message.MessageId))
        {
            message.MessageId = Guid.NewGuid().ToString();
        }
        string msg = string.Empty;
        await foreach (var item in SendChatMessageAsync(application, chatMessageContents, commonSetting))
        {
            if (item is null || (string.IsNullOrEmpty(item.content) && item.web_search is null)) continue;
            msg += item.content;
               
            await context.WriteOpenAiResultAsync(item.content, application.ChatModel, message.MessageId,
                message.MessageId);
        }
        await context.WriteEndAsync();
    }



    /// <summary>
    /// chat completions
    /// </summary>
    /// <param name="context"></param>
    public async Task CompletionsAsync(HttpContext context)
    {
        // 获取请求参数
        using var stream = new StreamReader(context.Request.Body);

        var message =
            JsonConvert.DeserializeObject<ChatCompletionRequest<ChatCompletionRequestMessage>>(
                await stream.ReadToEndAsync());
        context.Response.ContentType = "text/event-stream";
        if (message == null)
        {
            await context.WriteEndAsync("Invalid request");
            return;
        }

        var chatId = context.Request.Query["ChatId"].ToString();
        var token = context.Request.Headers.Authorization;

        if (chatId.IsNullOrEmpty()) chatId = message.ApplicationId;

        if (chatId.IsNullOrEmpty()) chatId = context.Request.Headers["applicationId"];
        // 获取分享Id
        var chatShareId = context.Request.Query["ChatShareId"].ToString();
        if (chatShareId.IsNullOrEmpty()) chatShareId = message.SharedId;

        if (chatShareId.IsNullOrEmpty()) chatShareId = context.Request.Headers["sharedId"];

        if (string.IsNullOrEmpty(chatShareId) && string.IsNullOrEmpty(chatId))
        {
            return;
        }

        // 识别token
        ChatApplicationDetailResponse chatApplicationDetailResponse = await chatApplicationService.Detail(chatId);
        if (chatApplicationDetailResponse == null)
        {
            await context.WriteEndAsync("应用Id不存在");
            return;
        }

        var requestToken = 0;

        var chatHistory = new ChatHistory();
        if (!string.IsNullOrEmpty(chatApplicationDetailResponse.Prompt))
        {
            chatHistory.AddSystemMessage(chatApplicationDetailResponse.Prompt);
        }

        var content = message.Messages.Last(x => !string.IsNullOrEmpty(x.Content));
        string question = content.Content;
        // 保存对话提问
        await chatApplicationService.CreateChatRecord(chatId, question, message.DialogId, "");
        // 使用知识库
        var sourceFile = new List<FileResource>();
        if (chatApplicationDetailResponse.WikiIds.Count > 0)
        {
            var success = await WikiPrompt(chatApplicationDetailResponse, content.Content,
                sourceFile, message, async x => { await context.WriteEndAsync(x); });
            if (!success) return;
        }

        // 需要处理 消息格式
        // 如果是需要 web 搜索的话 ，那么就处理消息内容
        message.Messages.ForEach(x =>
        {
            if (string.IsNullOrEmpty(x.Content)) return;
            requestToken += TokenHelper.ComputeToken(x.Content);
            chatHistory.Add(new ChatMessageContent(new AuthorRole(x.Role), x.Content));
        });

        var responseId = Guid.NewGuid().ToString("N");
        if (string.IsNullOrEmpty(message.MessageId))
        {
            message.MessageId = responseId;
        }

        var requestId = Guid.NewGuid().ToString("N");
        var output = new StringBuilder();


        try
        {
            AICommonSetting aiCommonSetting = await wikiSettingService.GetCommonSetting();
            if (aiCommonSetting == null)
            {
                await context.WriteErrorAsync("系统中的AI设置为空，无法使用该功能");
                return;
            }

            await foreach (var item in
                           SendChatMessageAsync(chatApplicationDetailResponse, chatHistory, aiCommonSetting))
            {
                if (item is null || (string.IsNullOrEmpty(item.content) && item.web_search is null)) continue;
                output.Append(item);
                await context.WriteOpenAiResultAsync(item, message.Model, requestId,
                    message.MessageId, sourceFiles: sourceFile?.Select(x => x.OriginName).ToList());
            }
        }
        catch (InvalidOperationException invalidOperationException)
        {
            await context.WriteEndAsync("对话异常：" + invalidOperationException.Message);
            logger.LogError(invalidOperationException, "对话异常");
            return;
        }
        catch (ArgumentException argumentException)
        {
            await context.WriteErrorAsync(argumentException.Message);
            logger.LogError(argumentException, "对话异常");
            return;
        }
        catch (Exception e)
        {
            logger.LogError(e, "对话异常");
            await context.WriteErrorAsync("对话异常：" + e.Message);
            return;
        }

        await context.WriteEndAsync();
    }


    /// <summary>
    /// 组装 wiki prompt 
    /// </summary>
    /// <param name="chatApplication"></param>
    /// <param name="content"></param>
    /// <param name="sourceFile"></param>
    /// <param name="module"></param>
    /// <param name="notFoundAction"></param>
    /// <returns></returns>
    private async Task<bool> WikiPrompt(ChatApplicationDetailResponse chatApplication,
        string content, List<FileResource> sourceFile,
        ChatCompletionRequest<ChatCompletionRequestMessage> module, Func<string, ValueTask> notFoundAction = null)
    {
        var filters = chatApplication.WikiIds
            .Select(x => new MemoryFilter().ByTag("wikiId", x)).ToList();
        var wikis = await wikiService.GetByIdsAsync(chatApplication.WikiIds);
        var setting = await wikiSettingService.GetCommonSetting();
        List<bool> progress = new();
        foreach (var wiki in wikis)
        {
            if ((wiki.VectorType ?? VectorType.None).Equals(VectorType.Mem0))
            {
                var data = await BuildWikiPromptByVectorMem0Async(wiki, chatApplication, module, sourceFile, content);
                progress.Add(data);
            }
            else
            {
                var data = await BuildWikiPromptByVectorNoneAsync(wiki, chatApplication, module, sourceFile, content,
                    filters, setting);
                progress.Add(data);
            }
        }

        if (progress.Exists(x => x))
        {
            return true;
        }

        await notFoundAction!.Invoke(chatApplication.NoReplyFoundTemplate);
        return false;
    }

    /// <summary>
    /// 组装 wiki prompt 
    /// </summary>
    /// <returns></returns>
    private async Task<bool> BuildWikiPromptByVectorNoneAsync(Aurora.AI.Wiki.Domain.Domain.Wikis.Aggregates.Wiki wiki,
        ChatApplicationDetailResponse chatApplication,
        ChatCompletionRequest<ChatCompletionRequestMessage> module,
        List<FileResource> sourceFile,
        string content, List<MemoryFilter> filters,
        AICommonSetting setting)
    {
        var memoryServerless = wikiMemoryService.CreateMemoryServerless(wiki.EmbeddingModel, wiki.Model, setting);
        List<string> fileIds = new List<string>();
        var result = await memoryServerless.SearchAsync(content, "wiki", filters: filters, limit: 3,
            minRelevance: chatApplication.Relevancy);
        string prompt = string.Empty;
        result.Results.ForEach(item =>
        {
            // 获取fileId
            var fileId = item.Partitions.Select(x => x.Tags.FirstOrDefault(x => x.Key == "fileId"))
                ?.FirstOrDefault(x => !x.Value.IsNullOrEmpty())
                .Value?.FirstOrDefault() ?? string.Empty;

            if (!fileId.IsNullOrWhiteSpace()) fileIds.Add(fileId);

            prompt += string.Join(Environment.NewLine, item.Partitions.Select(x => x.Text));
        });

        if (result.Results.Count == 0 &&
            !string.IsNullOrWhiteSpace(chatApplication.NoReplyFoundTemplate))
        {
            // await notFoundAction!.Invoke(chatApplication.NoReplyFoundTemplate);
            return false;
        }

        var tokens = TokenHelper.GetGptEncoding().Encode(prompt);
        // 这里可以有效的防止token数量超出限制，但是也会降低回复的质量
        prompt = TokenHelper.GetGptEncoding()
            .Decode(tokens.Take(chatApplication.MaxResponseToken).ToList());

        // 如果prompt不为空，则需要进行模板替换
        if (!prompt.IsNullOrEmpty())
            prompt = chatApplication.Template.Replace("{{quote}}", prompt)
                .Replace("{{question}}", content);

        // 在这里需要获取源文件
        if (fileIds.Count > 0 && chatApplication.ShowSourceFile)
        {
            var fileResult = await fileStorage.GetByIds(fileIds);

            sourceFile.AddRange(fileResult);
        }

        if (!prompt.IsNullOrEmpty())
        {
            // 删除最后一个消息
            module.Messages.RemoveAt(module.Messages.Count - 1);
            module.Messages.Add(new ChatCompletionRequestMessage
            {
                Content = prompt,
                Role = "user"
            });
        }

        return true;
    }

    /// <summary>
    /// 组装 wiki prompt 
    /// </summary>
    /// <returns></returns>
    private async Task<bool> BuildWikiPromptByVectorMem0Async(Aurora.AI.Wiki.Domain.Domain.Wikis.Aggregates.Wiki wiki,
        ChatApplicationDetailResponse chatApplication,
        ChatCompletionRequest<ChatCompletionRequestMessage> module,
        List<FileResource> sourceFile,
        string content)
    {
        string prompt = string.Empty;
        MemoryService memoryService = serviceProvider.GetRequiredService<mem0.NET.Services.MemoryService>();
        var fileIds = new List<string>();
        var values = await memoryService.SearchMemory(content, null, wiki.Id.ToString(), null, 3);
        values = values.Where(x => x.Score > chatApplication.Relevancy).ToList();
        values.ForEach(x =>
        {
            // 如果使用metaData那么可能会导致MaxToken超出限制。
            var metaData = x.MetaData["metaData"];
            prompt += metaData + Environment.NewLine;
        });
        if (values.Count == 0 && !string.IsNullOrWhiteSpace(chatApplication.NoReplyFoundTemplate))
        {
            // if (notFoundAction != null)
            // {
            //     await notFoundAction.Invoke(chatApplication.NoReplyFoundTemplate);
            // }
            return false;
        }

        var tokens = TokenHelper.GetGptEncoding().Encode(prompt);
        // 这里可以有效的防止token数量超出限制，但是也会降低回复的质量
        prompt = TokenHelper.GetGptEncoding()
            .Decode(tokens.Take(chatApplication.MaxResponseToken).ToList());

        // 如果prompt不为空，则需要进行模板替换
        if (!prompt.IsNullOrEmpty())
            prompt = chatApplication.Template.Replace("{{quote}}", prompt)
                .Replace("{{question}}", content);

        // 在这里需要获取源文件
        if (fileIds.Count > 0 && chatApplication.ShowSourceFile)
        {
            var fileResult = await fileStorage.GetByIds(fileIds);

            sourceFile.AddRange(fileResult);
        }

        if (!prompt.IsNullOrEmpty())
        {
            // 删除最后一个消息
            module.Messages.RemoveAt(module.Messages.Count - 1);
            module.Messages.Add(new ChatCompletionRequestMessage
            {
                Content = prompt,
                Role = "user"
            });
        }

        return true;
    }

    /// <summary>
    /// image generate
    /// </summary>
    /// <param name="context"></param>
    public async Task ImageGenerate(HttpContext context)
    {
        // 获取请求参数
        using var stream = new StreamReader(context.Request.Body);
        string val = await stream.ReadToEndAsync();
        var message =
            JsonConvert.DeserializeObject<ImagesCompletionRequest<ImageCreateRequest>>(
                val);
        context.Response.ContentType = "text/event-stream";
        if (message == null)
        {
            await context.WriteEndAsync("Invalid request");
            return;
        }

        var responseId = Guid.NewGuid().ToString("N");
        if (string.IsNullOrEmpty(message.Message.User))
        {
            message.Message.User = string.IsNullOrEmpty(message.MessageId) ? responseId : message.MessageId;
        }

        string question = message.Message.Prompt;

        ChatApplicationService chatApplicationService =
            context.RequestServices.GetRequiredService<ChatApplicationService>();
        string applicationId = message.ApplicationId;
        var application = await chatApplicationService.Detail(applicationId);
        if (application == null)
        {
            await context.WriteErrorAsync("无效应用");
            return;
        }

        // 保存对话提问
        await chatApplicationService.CreateChatRecord(application.Id, question, message.DialogId, "");


        var requestId = Guid.NewGuid().ToString("N");
        var output = new StringBuilder();
        ILogger logger = context.RequestServices.GetRequiredService<ILogger<OpenAiService>>();

        var imageGenerateService = context.RequestServices.GetRequiredService<AiImageGenerateService>();
        try
        {
            if (!string.IsNullOrEmpty(application.Prompt))
            {
                // 需要进行转换
                if (application.Prompt.Contains("{{question}}"))
                {
                    message.Message.Prompt = application.Prompt.Replace("{{question}}", message.Message.Prompt);
                }
                else
                {
                    message.Message.Prompt = application.Prompt + "," + message.Message.Prompt;
                }
            }

            message.Message.Model = application.ChatModel;

            WikiSettingService wikiSettingService = context.RequestServices.GetRequiredService<WikiSettingService>();
            AICommonSetting aiCommonSetting = await wikiSettingService.GetCommonSetting();
            if (aiCommonSetting == null)
            {
                await context.WriteErrorAsync("系统中的AI设置为空，无法使用该功能");
                return;
            }

            await SendImagesMessageAsync(context, message.Message, imageGenerateService, aiCommonSetting, application);
        }
        catch (UnauthorizedAccessException e)
        {
            logger.LogWarning(e, e.Message);
            context.Response.StatusCode = 401;
        }
        catch (ArgumentException argumentException)
        {
            await context.WriteErrorAsync(argumentException.Message);
            logger.LogError(argumentException, "生成图文异常");
            return;
        }
        catch (Exception e)
        {
            logger.LogError(e, "对话异常");
            await context.WriteErrorAsync(e.Message);
        }
    }


    /// <summary>
    /// video generate
    /// </summary>
    /// <param name="context"></param>
    public async Task VideoGenerate(HttpContext context)
    {
        try
        {
            // 获取请求参数
            using var stream = new StreamReader(context.Request.Body);
            string val = await stream.ReadToEndAsync();
            var message =
                AuroraAIJsonSerializer.Deserialize<VideosCompletionRequest<VideoCreateRequest>>(
                    val);
            context.Response.ContentType = "text/event-stream";
            if (message == null)
            {
                await context.WriteEndAsync("Invalid request");
                return;
            }

            var responseId = Guid.NewGuid().ToString("N");
            if (string.IsNullOrEmpty(message.Message.User))
            {
                message.Message.User = string.IsNullOrEmpty(message.MessageId) ? responseId : message.MessageId;
            }

            string question = message.Message.Prompt;

            ChatApplicationService chatApplicationService =
                context.RequestServices.GetRequiredService<ChatApplicationService>();
            string applicationId = message.ApplicationId;
            var application = await chatApplicationService.Detail(applicationId);
            if (application == null)
            {
                await context.WriteErrorAsync("无效应用");
                return;
            }

            // 保存对话提问
            await chatApplicationService.CreateChatRecord(application.Id, question, message.DialogId, message.Message.Path);

            ILogger logger = context.RequestServices.GetRequiredService<ILogger<OpenAiService>>();

            var service = context.RequestServices.GetRequiredService<AiVideoGenerateService>();
            try
            {
                if (!string.IsNullOrEmpty(application.Prompt))
                {
                    // 需要进行转换
                    if (application.Prompt.Contains("{{question}}"))
                    {
                        message.Message.Prompt = application.Prompt.Replace("{{question}}", message.Message.Prompt);
                    }
                    else
                    {
                        message.Message.Prompt = application.Prompt + "," + message.Message.Prompt;
                    }
                }

                message.Message.Model = application.ChatModel;

                WikiSettingService wikiSettingService =
                    context.RequestServices.GetRequiredService<WikiSettingService>();
                AICommonSetting aiCommonSetting = await wikiSettingService.GetCommonSetting();
                if (aiCommonSetting == null)
                {
                    await context.WriteErrorAsync("系统中的AI设置为空，无法使用该功能");
                    return;
                }

                await SendVideoMessageAsync(context, message.Message, service, aiCommonSetting);
            }
            catch (UnauthorizedAccessException e)
            {
                logger.LogWarning(e, e.Message);
                context.Response.StatusCode = 401;
            }
            catch (ArgumentException argumentException)
            {
                await context.WriteErrorAsync(argumentException.Message);
                logger.LogError(argumentException, "生成视频异常");
            }
            catch (Exception e)
            {
                logger.LogError(e, "生成视频异常");
                await context.WriteErrorAsync(e.Message);
            }
        }
        catch (Exception e)
        {
            logger.LogError(e, e.Message);
            await context.WriteErrorAsync(e.Message);
        }
    }

    /// <summary>
    /// 提问ai
    /// </summary>
    /// <param name="chatApplication">应用</param>
    /// <param name="chatHistory">历史聊天</param>
    /// <param name="setting"></param>
    /// <returns></returns>
    public async IAsyncEnumerable<OpenAIMixMessage> SendChatMessageAsync(
        ChatApplicationDetailResponse chatApplication,
        ChatHistory chatHistory, AICommonSetting setting)
    {
        var kernel = wikiMemoryService.CreateFunctionKernel(chatApplication.ChatModel, setting);
        // 设置温度
        var temperature = chatApplication.Temperature / 100; // 存的是0-100 需要缩小
        OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };

        if (chatApplication.EnableWebSearch)
        {
            settings.ExtensionData = new Dictionary<string, object>()
            {
                { "web_search", true }
            };
            chatHistory.Add(new ChatMessageContent(AuthorRole.User, AuroraAIJsonSerializer.Serialize(new
            {
                type = "web_search",
                web_search = new AuroraAIToolWebSearchDefinition()
                {
                    Enable = true,
                    SearchResult = true
                }
            })));
        }

        // todo 后续加上函数
        IChatCompletionService chat = kernel.GetRequiredService<IChatCompletionService>();
        await foreach (StreamingChatMessageContent item in chat.GetStreamingChatMessageContentsAsync(chatHistory,
                           settings))
        {
            string message = item.Content;
            if (string.IsNullOrEmpty(message)) continue;
            // 解析特殊的字符
            string val = AuroraAIJsonSerializer.GetFirstJsonValue(message?.ToString(), "content");
            // 解析为复杂对象
            OpenAIMixMessage openAiMixMessage = new();
            if (val is not null)
            {
                openAiMixMessage = AuroraAIJsonSerializer.Deserialize<OpenAIMixMessage>(message);
            }
            else
            {
                openAiMixMessage.content = message;
            }

            yield return openAiMixMessage;
        }
    }

    /// <summary>
    /// 构建汇总历史对话--暂时保留
    /// </summary>
    /// <param name="questions"></param>
    /// <param name="message"></param>
    /// <param name="kernel"></param>
    /// <returns></returns>
    private async Task<string> HistorySummarize(string questions, ChatCompletionRequest<ChatCompletionRequestMessage> message, Kernel kernel)
    {
        StringBuilder history = new StringBuilder();
        // 获取历史对话
        var historyMessage = message.Messages;
        foreach (var item in historyMessage)
        {
            if (item.Role.Equals("user") && !string.IsNullOrEmpty(item.Content))
            {
                history.Append($"user:{item.Content}{Environment.NewLine}");
            }
            else if (!string.IsNullOrEmpty(item.Content))
            {
                history.Append($"assistant:{item.Content}{Environment.NewLine}");
            }
        }
        KernelFunction sunFun = kernel.Plugins.GetFunction("ConversationSummaryPlugin", "SummarizeConversation");
        var summary = await kernel.InvokeAsync(sunFun, new() { ["input"] = $"内容是：{history.ToString()} {Environment.NewLine}请注意用中文总结" });
        string his = summary.GetValue<string>();
        string msg = $"历史对话:{his}{Environment.NewLine}{questions}";
        return msg;
    }


    /// <summary>
    /// video generate 
    /// </summary>
    /// <param name="context">应用</param>
    /// <param name="request">历史聊天</param>
    /// <param name="service">memory service</param>
    /// <param name="setting"></param>
    /// <returns></returns>
    private async ValueTask SendVideoMessageAsync(HttpContext context, VideoCreateRequest request,
        AiVideoGenerateService service, AICommonSetting setting)
    {
        // 发起 http 请求
        var data = await service.CreateVideoAsync(setting, request);
        data.id = request.User;
        if (!data?.successful ?? false)
        {
            await context.WriteErrorAsync(data.message);
            return;
        }

        string taskId = data.data;

        // 开始查询视频的结果
        DateTime time = DateTime.Now.AddMinutes(10); // 最长10分钟
        VideoCreateResponse response = new VideoCreateResponse();
        while (DateTime.Now <= time)
        {
            var queryResult = await service.QueryVideoAsync(setting, new VideoTaskQueryRequest()
            {
                Id = taskId,
                Model = request.Model
            });
            if (queryResult.finish)
            {
                response = queryResult;
                break;
            }

            await Task.Delay(TimeSpan.FromSeconds(1));
        }

        await context.WriteOpenAiResultAsync(AuroraAIJsonSerializer.Serialize(response.data), request.Model, data.id,
            data.id);
        await Task.Delay(100);
        await context.WriteEndAsync();
    }

    /// <summary>
    /// 提问ai
    /// </summary>
    /// <param name="context">应用</param>
    /// <param name="request">历史聊天</param>
    /// <param name="imageGenerateService">memory service</param>
    /// <param name="setting"></param>
    /// <param name="application"></param>
    /// <returns></returns>
    public async ValueTask SendImagesMessageAsync(HttpContext context, ImageCreateRequest request,
        AiImageGenerateService imageGenerateService, AICommonSetting setting, ChatApplicationDetailResponse application)
    {
        request.Size = OpenAIImagesOption.Size;
        // 发起 http 请求
        var data = await imageGenerateService.CreateImageAsync(setting, request);
        data.id = request.User;
        if (!data?.successful ?? false)
        {
            await context.WriteErrorAsync(data.message);
            return;
        }

        await context.WriteOpenAiResultAsync(data.data[0].Url, request.Model, data.id,
            data.id);
        // 根据图像生成图像对应的描述
        await SendImageAnalyMessageAsync(context, request, setting, application, data);

        await Task.Delay(100);
        await context.WriteEndAsync();
    }

    /// <summary>
    /// 发送图片解析
    /// </summary>
    /// <param name="context"></param>
    /// <param name="request"></param>
    /// <param name="setting"></param>
    /// <param name="application"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    private async Task SendImageAnalyMessageAsync(HttpContext context, ImageCreateRequest request,
        AICommonSetting setting, ChatApplicationDetailResponse application, ImageCreateResponse data)
    {
        // 根据图像生成图像对应的描述
        if (!string.IsNullOrEmpty(application.ImageAnalysisModel))
        {
            string prompt = string.IsNullOrEmpty(application.ImageAnalysisPrompt)
                ? "这是为你创作的图，详细解释说明一下图中的场景和细节以及现象"
                : application.ImageAnalysisPrompt;
            // WikiMemoryService wikiMemoryService = context.RequestServices.GetRequiredService<WikiMemoryService>();
            ChatHistory chatHistory = new ChatHistory();
            List<object> objects = new List<object>()
            {
                new
                {
                    type = "image_url",
                    image_url = new
                    {
                        url = data.data[0].Url
                    },
                    second_trans = "image_trans",
                },
                new
                {
                    type = "text",
                    text = prompt,
                    second_trans = "image_trans",
                }
            };
            chatHistory.Add(new ChatMessageContent(new AuthorRole("user"), JsonConvert.SerializeObject(objects)));
            await foreach (var item in SendChatMessageAsync(new ChatApplicationDetailResponse()
            {
                ChatModel = application.ImageAnalysisModel,
                Temperature = application.Temperature
            }, chatHistory, setting))
            {
                if (item is null || (string.IsNullOrEmpty(item.content) && item.web_search is null)) continue;
                await context.WriteOpenAiResultAsync(item.content, request.Model, data.id,
                    data.id);
            }
        }
    }


    #region qa

    /// <summary>
    /// QA问答解析大文本拆分多个段落
    /// </summary>
    /// <param name="prompt"></param>
    /// <param name="value"></param>
    /// <param name="model"></param>
    /// <param name="apiKey"></param>
    /// <param name="url"></param>
    /// <param name="memoryService"></param>
    /// <param name="setting"></param>
    /// <returns></returns>
    public static async IAsyncEnumerable<string> QaAsync(string prompt, string value, string model,
        string apiKey,
        string url,
        WikiMemoryService memoryService, AICommonSetting setting)
    {
        var kernel = memoryService.CreateFunctionKernel(apiKey, model, setting);

        var qaFunction = kernel.CreateFunctionFromPrompt(prompt, functionName: "QA", description: "QA问答");

#pragma warning disable KMEXP00
        var lines = TextChunker.SplitPlainTextLines(value, 299);
#pragma warning restore KMEXP00
#pragma warning disable KMEXP00
        var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, 4000);
#pragma warning restore KMEXP00

        foreach (var paragraph in paragraphs)
        {
            var result = await kernel.InvokeAsync(qaFunction, new KernelArguments
            {
                {
                    "input", paragraph
                }
            });

            yield return result.GetValue<string>();
        }
    }

    #endregion
}